use std::{
    collections::{HashMap, HashSet, VecDeque},
    fs,
};

use chrono::Local;
use regex::Regex;
use tree_sitter::{Node, Parser, Tree};
use walkdir::WalkDir;

#[derive(Debug)]
pub struct ContentAndNode {
    pub content: String,
    pub node_tree: Tree,
    pub class_node_index: (usize, usize),
    pub method_node_index: Option<Vec<(usize, usize)>>,
}

pub fn nodes_by_class_name_and_method(
    project_path: &str,
    full_class_name: &str,
    method_name_op: Option<&str>,
) -> Vec<ContentAndNode> {
    // java 解析器
    let mut parser = Parser::new();
    parser
        .set_language(&tree_sitter_java::LANGUAGE.into())
        .expect("tree_sitter_sequel init fail");

    // 获取符合的内容(文档，节点，代码索引列表)
    let mut contents: Vec<ContentAndNode> = WalkDir::new(project_path)
        .sort_by_file_name()
        .follow_links(true)
        .into_iter()
        .filter_map(|entry| {
            if let Ok(path) = entry {
                let full_path: String = path.path().display().to_string();
                if full_path.ends_with(".java") {
                    if let Ok(file_content) = fs::read_to_string(path.path()) {
                        let node_tree = parser.parse(&file_content, None).unwrap();
                        let root_node: &Node<'_> = &node_tree.root_node();

                        // 筛选出package
                        if let Some(package_declaration_node) =
                            super::base::node_by_type(&root_node, "package_declaration").get(0)
                        {
                            if let Some(scoped_identifier_node) = super::base::node_by_type(
                                &package_declaration_node,
                                "scoped_identifier",
                            )
                            .get(0)
                            {
                                // package name
                                let package_name = &file_content[scoped_identifier_node.start_byte()
                                    ..scoped_identifier_node.end_byte()];

                                // 筛选出class-node
                                let class_nodes =
                                    super::base::node_by_type(&root_node, "class_declaration");
                                let class_nodes: Vec<Node<'_>> = class_nodes
                                    .into_iter()
                                    .filter_map(|class_node| {
                                        let mut class_node_cursor = class_node.walk();
                                        let class_name_node_op = class_node
                                            .children(&mut class_node_cursor)
                                            .find(|item| item.kind() == "identifier");

                                        if let Some(class_name_node) = class_name_node_op {
                                            // class name
                                            let class_name = &file_content[class_name_node
                                                .start_byte()
                                                ..class_name_node.end_byte()];

                                            if format!("{package_name}.{class_name}")
                                                == full_class_name
                                            {
                                                return Some(class_node);
                                            } else {
                                                return None;
                                            }
                                        }

                                        return None;
                                    })
                                    .collect();

                                // 提取节点索引
                                // todo class node只有一个
                                if let Some(class_node) = class_nodes.get(0) {
                                    let class_node_index =
                                        (class_node.start_byte(), class_node.end_byte());
                                    return Some(ContentAndNode {
                                        content: file_content,
                                        node_tree: node_tree,
                                        class_node_index: class_node_index,
                                        method_node_index: None,
                                    });
                                }
                                return None;
                            }
                        }
                    }
                } else {
                    return None;
                }
            }
            None
        })
        .collect();

    // 筛选method
    if let Some(method_name) = method_name_op {
        contents = contents
            .into_iter()
            .filter_map(|item| {
                let file_content = &item.content;
                let node_tree = &item.node_tree;
                let class_node_op = super::base::node_by_start_and_end(
                    &node_tree.root_node(),
                    item.class_node_index.0,
                    item.class_node_index.1,
                );
                if let Some(class_node) = class_node_op {
                    // 查找 method_declaration,类下有多个方法
                    let method_nodes: Vec<Node<'_>> =
                        super::base::node_by_type(&class_node, "method_declaration");
                    let nodes = method_nodes
                        .into_iter()
                        .filter(|method_node| {
                            // 检查method节点的方法名是否正确
                            // 查找指定method_node
                            let mut method_node_cursor = method_node.walk();
                            let method_name_node_op = method_node
                                .children(&mut method_node_cursor)
                                .find(|method_node_itme| method_node_itme.kind() == "identifier");

                            // 检查方法名
                            if let Some(method_name_node) = method_name_node_op {
                                let now_method_name = &file_content
                                    [method_name_node.start_byte()..method_name_node.end_byte()];
                                if now_method_name == method_name {
                                    return true;
                                }
                            }
                            return false;
                        })
                        .collect::<Vec<Node<'_>>>();
                    // 提取节点索引
                    let nodes_index = nodes
                        .iter()
                        .map(|item| (item.start_byte(), item.end_byte()))
                        .collect();

                    return Some(ContentAndNode {
                        content: item.content,
                        node_tree: item.node_tree,
                        class_node_index: item.class_node_index,
                        method_node_index: Some(nodes_index),
                    });
                } else {
                    return None;
                }
            })
            .collect();
    }

    return contents;
}

// 查找"方法"的代码块中用到的 类+方法
pub fn seek_method<'a>(
    method_node: &Node<'_>,
    class_node: &Node<'_>,
    root_node: &Node<'_>,
    file_content: &str,
) -> Vec<(String, String)> {
    // 获取imports
    // ["com.a.b.C"]
    let imports: Vec<String> = super::base::get_import(&mut root_node.walk(), file_content)
        .iter()
        .filter_map(|item| {
            let re = Regex::new(r"import\s+([\w.]+);").unwrap();
            if let Some(caps) = re.captures(item) {
                return Some(
                    caps.get(1)
                        .map_or("".to_string(), |m| m.as_str().to_string())
                        .to_string(),
                );
            }
            return None;
        })
        .collect();

    // 搜索所有的方法调用
    let method_invocation_nodes: Vec<Node<'_>> =
        super::base::node_by_type(method_node, "method_invocation");

    // 遍历每个方法调用
    let result: Vec<(String, String)> = method_invocation_nodes
        .iter()
        .flat_map(|item| {
            // 获取identifier，第一个是调用方，第二个是方法名
            let method_invoke_identifier = super::base::node_by_type(item, "identifier");
            if method_invoke_identifier.len() >= 2 {
                let caller_node = method_invoke_identifier.get(0).unwrap();
                let method_node = method_invoke_identifier.get(1).unwrap();
                let caller = &file_content[caller_node.start_byte()..caller_node.end_byte()];
                let method = &file_content[method_node.start_byte()..method_node.end_byte()];

                // 查找所属的类型（短长度）
                // 从 local_variable_declaration（代码块中变量声明）和 field_declaration（类的属性属性声明）
                // todo 这里最多返回一条，简化代码返回所有匹配的数据
                let mut type_short: Vec<&str> = vec![caller];

                // 查找local_variable_declaration
                let local_variable_declaration_nodes: Vec<Node<'_>> =
                    super::base::node_by_type(method_node, "local_variable_declaration");

                let local_variable_declaration_find: Vec<&str> = local_variable_declaration_nodes
                    .iter()
                    .filter_map(|item| {
                        let type_identifier =
                            super::base::node_by_type_first(item, "type_identifier")
                                .map(|node_item| {
                                    &file_content[node_item.start_byte()..node_item.end_byte()]
                                })
                                .unwrap_or("");
                        let let_identifier = super::base::node_by_type_first(item, "identifier")
                            .map(|node_item| {
                                &file_content[node_item.start_byte()..node_item.end_byte()]
                            })
                            .unwrap_or("");
                        if let_identifier == caller {
                            return Some(type_identifier);
                        } else {
                            return None;
                        }
                    })
                    .collect();
                type_short.extend(local_variable_declaration_find);

                // 查找field_declaration
                let field_declaration_nodes: Vec<Node<'_>> =
                    super::base::node_by_type(class_node, "field_declaration");
                let field_declaration_nodes_find: Vec<&str> = field_declaration_nodes
                    .iter()
                    .filter_map(|item| {
                        let type_identifier =
                            super::base::node_by_type_first(item, "type_identifier")
                                .map(|node_item| {
                                    &file_content[node_item.start_byte()..node_item.end_byte()]
                                })
                                .unwrap_or("");
                        let variable_declarator =
                            super::base::node_by_type_first(item, "variable_declarator")
                                .map(|node_item| {
                                    &file_content[node_item.start_byte()..node_item.end_byte()]
                                })
                                .unwrap_or("");
                        if variable_declarator == caller {
                            return Some(type_identifier);
                        } else {
                            return None;
                        }
                    })
                    .collect();
                type_short.extend(field_declaration_nodes_find);

                let class_and_method: Vec<(String, String)> = type_short
                    .iter()
                    .filter_map(|class_short_name| {
                        // 从import查询类的全路径
                        let class_full_name_op = imports
                            .iter()
                            .find(|item| item.ends_with(class_short_name))
                            .map(|item| item.to_string());
                        if let Some(class_full_name) = class_full_name_op {
                            return Some((class_full_name, method.to_string()));
                        } else {
                            return None;
                        }
                    })
                    .collect();
                return class_and_method;
            }
            return vec![];
        })
        .collect();

    return result;
}

// 查找"类"的代码块中用到的 类+方法
pub fn seek_class<'a>(
    class_node: &Node<'_>,
    root_node: &Node<'_>,
    file_content: &str,
) -> Vec<(String, String)> {
    // 获取imports
    // ["com.a.b.C"]
    let imports: Vec<String> = super::base::get_import(&mut root_node.walk(), file_content)
        .iter()
        .filter_map(|item| {
            let re = Regex::new(r"import\s+([\w.]+);").unwrap();
            if let Some(caps) = re.captures(item) {
                return Some(
                    caps.get(1)
                        .map_or("".to_string(), |m| m.as_str().to_string())
                        .to_string(),
                );
            }
            return None;
        })
        .collect();

    // 搜索所有的方法调用
    let method_invocation_nodes: Vec<Node<'_>> =
        super::base::node_by_type(class_node, "method_invocation");

    // 遍历每个方法调用
    let result: Vec<(String, String)> = method_invocation_nodes
        .iter()
        .flat_map(|item| {
            // 获取identifier，第一个是调用方，第二个是方法名
            let method_invoke_identifier = super::base::node_by_type(item, "identifier");
            if method_invoke_identifier.len() >= 2 {
                let caller_node = method_invoke_identifier.get(0).unwrap();
                let method_node = method_invoke_identifier.get(1).unwrap();
                let caller = &file_content[caller_node.start_byte()..caller_node.end_byte()];
                let method = &file_content[method_node.start_byte()..method_node.end_byte()];

                // 查找所属的类型（短长度）
                // 从 field_declaration（类的属性属性声明）
                // todo 这里最多返回一条，简化代码返回所有匹配的数据
                let mut type_short: Vec<&str> = vec![caller];

                // 查找field_declaration
                let field_declaration_nodes: Vec<Node<'_>> =
                    super::base::node_by_type(class_node, "field_declaration");
                let field_declaration_nodes_find: Vec<&str> = field_declaration_nodes
                    .iter()
                    .filter_map(|item| {
                        let type_identifier =
                            super::base::node_by_type_first(item, "type_identifier")
                                .map(|node_item| {
                                    &file_content[node_item.start_byte()..node_item.end_byte()]
                                })
                                .unwrap_or("");
                        let variable_declarator =
                            super::base::node_by_type_first(item, "variable_declarator")
                                .map(|node_item| {
                                    &file_content[node_item.start_byte()..node_item.end_byte()]
                                })
                                .unwrap_or("");
                        if variable_declarator == caller {
                            return Some(type_identifier);
                        } else {
                            return None;
                        }
                    })
                    .collect();
                type_short.extend(field_declaration_nodes_find);

                let class_and_method: Vec<(String, String)> = type_short
                    .iter()
                    .filter_map(|class_short_name| {
                        // 从import查询类的全路径
                        let class_full_name_op = imports
                            .iter()
                            .find(|item| item.ends_with(class_short_name))
                            .map(|item| item.to_string());
                        if let Some(class_full_name) = class_full_name_op {
                            return Some((class_full_name, method.to_string()));
                        } else {
                            return None;
                        }
                    })
                    .collect();
                return class_and_method;
            }
            return vec![];
        })
        .collect();

    return result;
}

// 递归获取用到的代码
pub fn recursion_get_used_code(
    project_path: &str,
    full_class_name: &str,
    method_name_op: Option<&str>,
    output_imports: bool,
) -> String {
    // java 解析器
    let mut parser = Parser::new();
    parser
        .set_language(&tree_sitter_java::LANGUAGE.into())
        .expect("tree_sitter_sequel init fail");

    let mut codes: Vec<String> = vec![];
    let mut key_set = HashSet::<String>::new();
    let mut class_path: VecDeque<(String, Option<String>)> = VecDeque::new();

    // 构造"类+方法"的缓存 com.x.Class#method:(file_path, (17, 45))
    let code_cache_line: Vec<(String, String, (usize, usize))> =
        super::base::code_cache_line(project_path);
    let mut code_cache: HashMap<String, Vec<(String, (usize, usize))>> = HashMap::new();
    for item in code_cache_line {
        code_cache
            .entry(item.0)
            .or_insert_with(Vec::new)
            .push((item.1, item.2));
    }

    // 构造“接口实现”的缓存
    let implement_cache_line = super::base::implement_cache_line(project_path);
    let mut implement_cache: HashMap<String, Vec<String>> = HashMap::new();
    for item in implement_cache_line {
        implement_cache
            .entry(item.0)
            .or_insert_with(Vec::new)
            .push(item.1);
    }

    // 放入第一条数据
    class_path.push_back((
        full_class_name.to_string(),
        method_name_op.map(|item| item.to_string()),
    ));

    loop {
        let item_item_op = class_path.pop_front();
        if let Some(item_item) = item_item_op {
            // 保存key
            let code_key = &if let Some(method_name) = item_item.1 {
                format!("{}#{}", &item_item.0, method_name)
            } else {
                format!("{}", &item_item.0)
            };

            // class key
            let class_key = item_item.0;
            if let Some(class_nodes) = code_cache.get(&class_key) {
                // class node一般就一个
                for class_node in class_nodes {
                    let file_name = &class_node.0;
                    let class_node_index = class_node.1;
                    if let Ok(class_file_content) = &fs::read_to_string(&file_name) {
                        let class_node_tree = parser.parse(&class_file_content, None).unwrap();
                        let class_root_node: &Node<'_> = &class_node_tree.root_node();
                        // 找到class node
                        if let Some(class_node) = super::base::node_by_start_and_end(
                            class_root_node,
                            class_node_index.0,
                            class_node_index.1,
                        ) {
                            // 输出相关代码
                            if let Some(cache_lines) = code_cache.get(code_key) {
                                // 已经遍历过
                                let insert_result = key_set.insert(code_key.to_string());
                                if !insert_result {
                                    continue;
                                }

                                // 代码块说明
                                codes.push(format!("// {}", &code_key));

                                // 输出import
                                if output_imports {
                                    let imports = super::base::get_import(
                                        &mut class_root_node.walk(),
                                        &class_file_content,
                                    );
                                    codes.push(format!("{}", imports.join("\n")));
                                }

                                // 遍历找到的多个代码
                                for cache_line in cache_lines {
                                    // 读取文件（一般都是ok,除非在很短的间隔内删除）
                                    if let Ok(file_content) = &fs::read_to_string(&cache_line.0) {
                                        // 方法块索引
                                        let code_block_index = cache_line.1;

                                        // 保存class或method代码
                                        let code_block = file_content
                                            [code_block_index.0..code_block_index.1]
                                            .to_string();
                                        codes.push(code_block);

                                        // 查找关联的代码
                                        let code_node_tree =
                                            parser.parse(&file_content, None).unwrap();
                                        let code_root_node: &Node<'_> = &code_node_tree.root_node();
                                        let relate_class_and_method =
                                            if let Some(method_name) = method_name_op {
                                                // 查找方法中关联的代码
                                                if let Some(method_node) =
                                                    super::base::node_by_start_and_end(
                                                        code_root_node,
                                                        code_block_index.0,
                                                        code_block_index.1,
                                                    )
                                                {
                                                    // 查找关联代码 (class-name, method-name)
                                                    let ms = seek_method(
                                                        &method_node,
                                                        &class_node,
                                                        code_root_node,
                                                        file_content,
                                                    );
                                                    ms
                                                } else {
                                                    vec![]
                                                }
                                            } else {
                                                // 查找类中关联的代码
                                                if let Some(class_node) =
                                                    super::base::node_by_start_and_end(
                                                        code_root_node,
                                                        code_block_index.0,
                                                        code_block_index.1,
                                                    )
                                                {
                                                    let cs: Vec<(String, String)> = seek_class(
                                                        &class_node,
                                                        code_root_node,
                                                        file_content,
                                                    );
                                                    cs
                                                } else {
                                                    vec![]
                                                }
                                            };

                                        // 放入缓存队列
                                        for ms_item in relate_class_and_method {
                                            // 查找接口实现类
                                            let empty_vec = vec![];
                                            let impl_class_list: &Vec<String> = implement_cache
                                                .get(&ms_item.0)
                                                .unwrap_or(&empty_vec);

                                            // 保存当前类
                                            class_path
                                                .push_back((ms_item.0, Some(ms_item.1.clone())));

                                            // 保存实现类
                                            for impl_class in impl_class_list {
                                                class_path.push_back((
                                                    impl_class.clone(),
                                                    Some(ms_item.1.clone()),
                                                ));
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            // 分隔符
            codes.push("\n".to_string());
        } else {
            break;
        }
    }

    return codes.join("\n");
}

#[test]
fn test_nodes_by_class_name_and_method() {
    let cns: Vec<ContentAndNode> = nodes_by_class_name_and_method(
        "./assets",
        "com.demo.lino.admin.AdminApplication",
        Some("create"),
    );

    // 解析出代码
    let all_content = cns
        .into_iter()
        .map(|item| {
            let content = &item.content;
            let ri: Vec<String> = item
                .method_node_index
                .unwrap_or(vec![])
                .iter()
                .map(|index| {
                    let s = &content[index.0..index.1];
                    return s.to_string();
                })
                .collect();
            return ri.join("\n");
        })
        .collect::<Vec<String>>()
        .join("\n");

    println!("{all_content}");
}

#[test]
fn test_seek_method() {
    let cns: Vec<ContentAndNode> = nodes_by_class_name_and_method(
        "./assets",
        "com.demo.lino.admin.AdminApplication",
        Some("create"),
    );
    let ms: Vec<(String, String)> = cns
        .iter()
        .filter_map(|item| {
            let file_content = &item.content;
            let root_node = &item.node_tree.root_node();
            let class_node_index = &item.class_node_index;
            if let Some(class_node) = super::base::node_by_start_and_end(
                root_node,
                class_node_index.0,
                class_node_index.1,
            ) {
                let ms: Vec<(String, String)> = item
                    .method_node_index
                    .as_deref()
                    .unwrap_or(&vec![])
                    .iter()
                    .flat_map(|&method_index_item| {
                        if let Some(method_node) = super::base::node_by_start_and_end(
                            root_node,
                            method_index_item.0,
                            method_index_item.1,
                        ) {
                            let ms =
                                seek_method(&method_node, &class_node, root_node, file_content);
                            return ms;
                        }
                        return vec![];
                    })
                    .collect();
                return Some(ms);
            }
            None
        })
        .flat_map(|item| item)
        .collect();

    // 显示
    let ms = ms
        .iter()
        .map(|item| format!("{}#{}", item.0, item.1))
        .collect::<Vec<String>>();
    println!("{}", ms.join("\n"));
}

#[test]
fn test_recursion_get_used_code() {
    let codes = recursion_get_used_code(
        "/home/x/company/国电一期/server",
        "com.lingshu.infra.framework.security.controller.LoginController",
        Some("login"),
        true,
    );
    println!("{codes}");
}

#[test]
fn test_seek_class() {
    let cns: Vec<ContentAndNode> =
        nodes_by_class_name_and_method("./assets", "com.demo.lino.admin.AdminApplication", None);
    let ms: Vec<(String, String)> = cns
        .iter()
        .filter_map(|item| {
            let file_content = &item.content;
            let root_node = &item.node_tree.root_node();
            let class_node_index = &item.class_node_index;
            if let Some(class_node) = super::base::node_by_start_and_end(
                root_node,
                class_node_index.0,
                class_node_index.1,
            ) {
                let cs: Vec<(String, String)> = seek_class(&class_node, root_node, file_content);
                Some(cs)
            } else {
                None
            }
        })
        .flat_map(|item| item)
        .collect();

    // 显示
    let ms = ms
        .iter()
        .map(|item| format!("{}#{}", item.0, item.1))
        .collect::<Vec<String>>();
    println!("{}", ms.join("\n"));
}

#[test]
fn test_parse_method() {
    let code = r#"DeviceProofResponse detail (Long id) {
            DeviceDataProofDO dataProofDO = deviceDataProofRepo.getById(id);
            if (dataProofDO == null) {
                throw new ApiException("数据不存在");
            }
            return BeanUtil.copyProperties(dataProofDO, DeviceProofResponse.class);
            }"#;

    // java 解析器
    let mut parser = Parser::new();
    parser
        .set_language(&tree_sitter_java::LANGUAGE.into())
        .expect("tree_sitter_sequel init fail");

    let node_tree = parser
        .parse(
            fs::read_to_string("/tmp/a7a839e4b/1.txt")
                .unwrap_or("".to_string())
                .as_str(),
            None,
        )
        .unwrap();
    let root_node: Node<'_> = node_tree.root_node();
    println!("node_tree {node_tree:#?}");
}
